

/**
 * Copyright (2024, ) Institute of Software, Chinese Academy of Sciences
 * author: wuheng@iscas.ac.cn
 * since:  0.1.0
 **/

use diesel::pg::PgConnection;
use diesel::SqliteConnection;
use diesel::RunQueryDsl;
use diesel::result::Error;
use serde_json::Value;
use diesel::sql_types::{Jsonb, Text};

pub fn insert_sqlite3_object(conn: &mut SqliteConnection, table: &str, data: Value) -> Result<bool, Error> {
    use diesel::sql_query;

    let name_value = data["name"].as_str().ok_or(Error::NotFound)?;
    let namespace_value = data["namespace"].as_str().ok_or(Error::NotFound)?;
    let apigroup_value = data["apigroup"].as_str().ok_or(Error::NotFound)?;
    let data_value = data["data"].to_string();

    let query = sql_query(generate_insert_sqlite3_object_sql(table))
        .bind::<Text, _>(name_value)
        .bind::<Text, _>(namespace_value)
        .bind::<Text, _>(apigroup_value)
        .bind::<Text, _>(&data_value);

    match query.execute(conn) {
        Ok(_) => Ok(true),
        Err(e) => Err(e),
    }
}

pub fn insert_postgres_object(conn: &mut PgConnection, table: &str, data: Value) -> Result<bool, Error> {
    use diesel::sql_query;

    let name_value = data["name"].as_str().ok_or(Error::NotFound)?;
    let namespace_value = data["namespace"].as_str().ok_or(Error::NotFound)?;
    let apigroup_value = data["apigroup"].as_str().ok_or(Error::NotFound)?;
    let data_value = data["data"].to_string();

    let query = sql_query(generate_insert_postgres_object_sql(table))
        .bind::<Text, _>(name_value)
        .bind::<Text, _>(namespace_value)
        .bind::<Text, _>(apigroup_value)
        .bind::<Text, _>(&data_value);

    match query.execute(conn) {
        Ok(_) => Ok(true),
        Err(e) => Err(e),
    }
}

fn generate_insert_postgres_object_sql(table_name: &str) -> String {
    format!(
        "INSERT INTO {} (name, namespace, apigroup, data, created, updated)
        VALUES ($1, $2, $3, $4::json, NOW(), NOW());",
        table_name
    )
}

fn generate_insert_sqlite3_object_sql(table_name: &str) -> String {
    format!(
        "INSERT INTO {} (name, namespace, apigroup, data, created, updated)
        VALUES ($1, $2, $3, $4::json, DATETIME('now'), DATETIME('now'));",
        table_name
    )
}

pub fn create_posgres_table(conn: &mut PgConnection, table: &str) -> Result<usize, Error> {
    let sql = format!("{}", generate_create_table_sql(table));
    diesel::sql_query(sql).execute(conn)
}

pub fn create_sqlite3_table(conn: &mut SqliteConnection, table: &str) -> Result<usize, Error> {
    let sql = format!("{}", generate_create_table_sql(table));
    diesel::sql_query(sql).execute(conn)
}

fn generate_create_table_sql(table_name: &str) -> String {
    format!(
        "CREATE TABLE {} (
            name character varying(256) NOT NULL,
            namespace character varying(256) NOT NULL,
            apigroup character varying(256) NOT NULL,
            data json NOT NULL,
            created timestamp NOT NULL,
            updated timestamp NOT NULL,
            PRIMARY KEY (name, namespace, apigroup)
        );",
        table_name
    )
}